This is actually a valid requirement in many systems today which want
to execute tasks parallelly but also want some determinism from time to
time.
For example, a mobile company would want to process subscription
events of multiple users parallelly but would want to execute events of a
single user one at a time.
One solution is to of course write everything to get executed on a
single thread. Another solution is deterministic threading. I have
written a simple library in Java that can be used to achieve the
behavior I have described in the above example. Take a look at this- https://github.com/mukulbansal93/deterministic-threading.
Now, having said that, the actual allocation of CPU to a thread or
process is in the hands of the OS. So, it is possible that the threads
get the CPU cycles in a different order every time you run the same
program. So, you cannot achieve the determinism in the order the threads
are allocated CPU cycles. However, by delegating tasks effectively
amongst threads such that sequential tasks are assigned to a single
thread, you can achieve determinism in overall task execution.
Also, to answer your question about the simulation of a crash. All
modern CPU scheduling algorithms are free from starvation. So, each and
every thread is bound to get guaranteed CPU cycles. Now, it is possible
that your crash was a result of the execution of a certain sequence of
threads on a single CPU. There is no way to rerun that same execution
order or rather the same CPU cycle allocation order. However, the
combination of modern CPU scheduling algorithms being starvation-free
and Murphy's law will help you simulate the error if you run your code
enough times.
PS, the definition of enough times is quite vague and
depends on a lot of factors like execution cycles need by the entire
program, number of threads, etc. Mathematically speaking, a crude way to
calculate the probability of simulating the same error caused by the
same execution sequence is on a single processor is-
1/Number of ways to execute all atomic operations of all defined threads
For instance, a program with 2 threads with 2 atomic instructions
each can be allocated CPU cycles in 4 different ways on a single
processor. So probability would be 1/4.